# @Time   : 2022/3/7 13:41
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^
# @Time   : 2022/1/18 15:00
# @Author : Fioman
# @Phone  : 13149920693
# @Tips   : Talk is Cheap,Show me the code! ^_^^_^

"""
二拼板的算法,主要包括首板尺寸确认,两拼板的识别问题,获取切线的函数
"""
import time

import os
from db_tools.db_handler import DbHandler
from vision_process.image_process_common import *
from vision_process.calc_middle_line import *

db = DbHandler()
cp = ConfigParams()
upDownSlice6p = int(-20 * cp.mm2pix)
leftRightSlice6p = int(35 * cp.mm2pix)
jointLineExtend = 20
innerToEdgeThres = 6  # 单位mm
minLineLength = int(20 * cp.mm2pix)  # 线条最短是多少,50个mm
lineLengthMin = 20 * cp.mm2pix
maxLineGap = 5

tryBeginIndex = 1

calcArgs6pin = {
    "1": [[2], 10, 11, 8, 15, [120, 70, 40], 0.2],
    "2": [[10, 120], 17, 17, 8, 20, [90, 30, 10], 0.2],
    "3": [[5], 17, 15, 10, 25, [120, 80, 40], 0.4],
    "4": [[0], 17, 11, 8, 20, [120, 70, 50], 0.3]
    # "4": [3, 17, 17, 15, 15, 100, 0.5],
    # "5": [5, 17, 17, 18, 18, 150, 0.5],
    # "6": [13, 17, 17, 30, 30, 8, 0.5],
    # "7": [3, 17, 17, 15, 15, 20, 0.5],
}


def get_inner_board_for_size_check_6p(board, jointLine1, jointLine2, width, height, calcThresBig):
    """
    六拼板尺寸确认的时候获取内板信息
    :param upLeftBoard:
    :param jointLine1:
    :param jointLine2:
    :param width:
    :param height:
    :param calcThresBig:
    :return:
    """
    imageHeight, imageWidth = board.shape[:2]
    moveWidth = int(imageWidth * 0.3)
    moveHeight = int(imageHeight * 0.3)
    boardColor = cv.cvtColor(board.copy(), cv.COLOR_GRAY2BGR)
    sizeOkRes = []
    calcArgs = calcArgs6pin
    for tryTimes in range(tryBeginIndex, len(calcArgs.keys()) + 1):
        cv.destroyAllWindows()
        gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate = calcArgs.get(str(tryTimes))
        print("进行第{}次计算,计算参数:(高斯半径:{}),(方差核大小:{}),(膨胀腐蚀核:{}),(膨胀腐蚀次数:{}),(腐蚀膨胀次数:{}),(阈值offset:{}),(scharr比例:{})".format(
            tryTimes, gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate))
        if len(gaussianR) == 1:
            if gaussianR[0] == 0:
                blurred = board.copy()
            else:
                blurred = cv.GaussianBlur(board, (0, 0), gaussianR[0])
        else:
            d, colorSigma = gaussianR
            spaceSigma = int(d / 2)
            blurred = cv.bilateralFilter(board, d, colorSigma, spaceSigma)

        if scharrRate == 0:
            scharrXY = blurred.copy()
        else:
            scharrX = cv.Scharr(blurred, cv.CV_64F, 1, 0)
            scharrY = cv.Scharr(blurred, cv.CV_64F, 0, 1)
            scharrX = cv.convertScaleAbs(scharrX)
            scharrY = cv.convertScaleAbs(scharrY)
            scharrXY = cv.addWeighted(scharrX, scharrRate, scharrY, scharrRate, 0)
            scharrXY = cv.bitwise_and(scharrXY, jointLine1)
        image_show("ScharrXY", scharrXY)
        img32 = np.float32(scharrXY)
        square1 = cv.blur(np.multiply(img32, img32), (squareR, squareR))
        square2 = np.multiply(cv.blur(img32, (squareR, squareR)), cv.blur(img32, (squareR, squareR)))
        squareDif32 = np.subtract(square1, square2)
        squareDif = squareDif32.copy()
        np.clip(squareDif32, 0, 255, out=squareDif)
        squareDif = squareDif.astype("uint8")
        image_show("SquareDif", squareDif)

        # 1.进行膨胀腐蚀,分割图像
        contourImg = squareDif.copy()
        kernelUsed = cv.getStructuringElement(cv.MORPH_RECT, (dilateKernel, dilateKernel))
        contourImg = cv.dilate(contourImg, kernelUsed, iterations=dilateTimes)
        contourImg = cv.erode(contourImg, kernelUsed, iterations=dilateTimes)
        image_show("squareDifDilateErode", contourImg)

        squareDifErode = contourImg.copy()
        for index, thresOffset in enumerate(thresOffsetList):
            cv.destroyAllWindows()
            image_show("squareDifDilateErode", squareDifErode)
            # 2. 根据阈值进行分割
            thresUsed = squareDifErode[moveHeight:int(contourImg.shape[0] - moveHeight),
                        moveWidth:contourImg.shape[1] - moveWidth]
            print("第{}个阈值,使用阈值 thresOffset = {}".format(index + 1, thresOffset))
            _, contourImg = cv.threshold(squareDifErode, thresOffset, 255, cv.THRESH_BINARY)

            # 3. 处理拼接处
            if scharrRate == 0:
                contourImg = cv.subtract(contourImg, jointLine2)

            # 4. 进行泛洪填充
            mask = np.zeros((contourImg.shape[0] + 2, contourImg.shape[1] + 2), dtype=np.uint8)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] // 2, contourImg.shape[0] // 2), 150)
            floodFill = np.zeros(contourImg.shape, dtype=np.uint8)
            floodFill[contourImg == 150] = 250
            image_show("FloodFill", floodFill)

            # 5.进行腐蚀膨胀,去除掉边界的噪点
            floodFill = cv.erode(floodFill, kernelUsed, iterations=erodeTimes)
            floodFill = cv.dilate(floodFill, kernelUsed, iterations=erodeTimes)
            image_show("FloodFillErodeDilate", floodFill)

            # 去除掉四个角的影响
            cv.rectangle(floodFill, (0, 0), (moveWidth, moveHeight), 0, -1)
            cv.rectangle(floodFill, (floodFill.shape[1], 0), (floodFill.shape[1] - moveWidth, moveHeight), 0, -1)
            cv.rectangle(floodFill, (0, floodFill.shape[0] - moveHeight), (moveWidth, floodFill.shape[0]), 0, -1)
            cv.rectangle(floodFill, (floodFill.shape[1] - moveWidth, floodFill.shape[0] - moveHeight),
                         (floodFill.shape[1], floodFill.shape[0]), 0, -1)
            image_show("MoveAngle", floodFill)

            res = check_inner_board_for_size_check(floodFill, width, height, calcThresBig, boardColor)
            print("计算结果:{},info:{},尺寸:{},{},误差:{}".format(res["result"], res["info"], res["calcSize"],
                                                                  (int(res["calcSize"][0] * cp.mm2pix), int(res["calcSize"][1] * cp.mm2pix)),
                                                                  res["calcError"]))
            if res["result"] != "error":
                sizeOkRes.append(res)
                continue
            elif res["result"] == "big":
                continue
            elif res["result"] == "small":
                continue
    else:
        sizeList = []
        boxList = []
        if len(sizeOkRes) >= 1:
            resOkSorted = sorted(sizeOkRes, key=lambda x: np.sum([abs(x["calcError"][0]), abs(x["calcError"][1])]))
            for res in resOkSorted:
                sizeList.append(res["calcSize"])
                boxList.append(res["box"])
            return "ok", sizeList, boxList
        else:
            return "error", [], []


def check_inner_board_for_size_check(boardMoveAngle, width, height, calcThresBig, boardColor):
    """
    尺寸确认那里的识别检测,这里会把识别的尺寸无论是偏大还是偏小,只要找到的是对的就返回给.
    :param boardMoveAngle:最后处理掉的包含内板的二值图像
    :param width:内板的宽
    :param height:内板的高
    :param calcThresBig:偏大阈值,首次尺寸确认的时候只使用偏大阈值
    :param boardColor:
    :return:
    """
    # 尺寸确认的时候,只使用偏大阈值
    useImage = boardColor.copy()
    totalHeightPix, totalWidthPix = boardMoveAngle.shape[:2]
    boardArea = width * height
    totalWidthMm = round(totalWidthPix / cp.mm2pix, 2)
    totalHeightMm = round(totalHeightPix / cp.mm2pix, 2)
    res = {
        "result": "error",
        "box": None,
        "info": "",
        "calcSize": (totalWidthMm, totalHeightMm),
        "calcError": (0, 0),
    }
    cnts, _ = cv.findContours(boardMoveAngle.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cntsSorted = sorted(cnts, key=cv.contourArea, reverse=True)
    try:
        _, (w, h), _ = cv.minAreaRect(cntsSorted[0])
        areaFinded = w * h
        if len(cnts) == 0:
            res["result"] = "error"
            res["info"] = "找内板失败,没有找到任何轮廓"
            res["calcSize"] = (totalWidthMm, totalHeightMm)
            res["calcError"] = (round(totalWidthMm - width / cp.mm2pix, 2), round(totalHeightMm - height / cp.mm2pix, 2))
            return res
        elif 1.3 * boardArea > areaFinded > 0.8 * boardArea:
            rectBox = cv.minAreaRect(cntsSorted[0])
            rectBoxPoints = np.intp(cv.boxPoints(rectBox))
            cv.drawContours(useImage, [rectBoxPoints], -1, (0, 255, 0), 3)
            image_show("InnerBoardFinded", useImage)
            leftTop, rightTop, rightBottom, leftBottom = get_rect_points_clockwise(rectBoxPoints)
            widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)  # 找到的宽,单位mm
            heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)  # 找到的高,单位mm
            widthError, heightError = round(widthFinded - width / cp.mm2pix, 2), round(heightFinded - height / cp.mm2pix, 2)
            res["calcSize"] = (widthFinded, heightFinded)
            res["calcError"] = (widthError, heightError)
            # 过滤掉一定是错误的线.第一,如果找到的两个顶点
            # 如果找到的第一边的一个顶点,太接近物料的顶点,就认为这条线肯定是找错了.

            widthMax = width / cp.mm2pix + calcThresBig
            widthMin = width / cp.mm2pix - calcThresBig
            heightMax = height / cp.mm2pix + calcThresBig
            heightMin = height / cp.mm2pix - calcThresBig
            res["box"] = [leftTop, rightTop, rightBottom, leftBottom]

            if widthFinded > widthMax:
                rightPosOffset = abs(get_two_points_middle(rightTop, rightBottom)[0] - totalWidthPix)
                leftPosOffset = get_two_points_middle(leftTop, leftBottom)[0]
                if abs(leftPosOffset) > 5 * cp.mm2pix and rightPosOffset < 5 * cp.mm2pix:
                    # 右侧找不到位置,推测第二边
                    newBox = get_new_box_for_no_middle(res["box"], "2", width)
                    leftTop, rightTop, rightBottom, leftBottom = newBox
                    widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)  # 找到的宽,单位mm
                    heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)  # 找到的高,单位mm
                    widthError, heightError = round(widthFinded - width / cp.mm2pix, 2), round(heightFinded - height / cp.mm2pix, 2)
                    res["calcSize"] = (widthFinded, heightFinded)
                    res["calcError"] = (widthError, heightError)
                    res["box"] = newBox
                    useImage = boardColor.copy()
                    cv.drawContours(useImage, [np.array(newBox)], -1, (0, 255, 0), 3)
                    image_show("InnerBoardFindedByExtend_2", useImage)

            if heightFinded > heightMax:
                topPosOffset = abs(get_two_points_middle(leftTop, rightTop)[1])
                bottomPosOffset = abs(get_two_points_middle(leftBottom, rightBottom)[1])
                if topPosOffset > 5 * cp.mm2pix and bottomPosOffset > totalHeightPix - 10 * cp.mm2pix:
                    newBox = get_new_box_for_no_middle(res["box"], "3", height)
                    leftTop, rightTop, rightBottom, leftBottom = newBox
                    widthFinded = round(get_two_point_distance(leftTop, rightTop) / cp.mm2pix, 2)  # 找到的宽,单位mm
                    heightFinded = round(get_two_point_distance(leftTop, leftBottom) / cp.mm2pix, 2)  # 找到的高,单位mm
                    widthError, heightError = round(widthFinded - width / cp.mm2pix, 2), round(heightFinded - height / cp.mm2pix, 2)
                    res["calcSize"] = (widthFinded, heightFinded)
                    res["calcError"] = (widthError, heightError)
                    res["box"] = newBox
                    useImage = boardColor.copy()
                    cv.drawContours(useImage, [np.array(newBox)], -1, (0, 255, 0), 3)
                    image_show("InnerBoardFindedByExtend_3", useImage)

            if widthFinded > widthMax or heightFinded > heightMax:
                res["result"] = "big"
                res["info"] = "识别尺寸过大"
                return res

            if widthFinded < widthMin or heightFinded < heightMin:
                res["result"] = "small"
                res["info"] = "识别尺寸过小"
                return res

            if get_two_points_middle(leftTop, rightTop)[1] < 8 * cp.mm2pix:
                res["result"] = "error"
                res["info"] = "{}框 找到的内板第一边,太靠近上边缘,判定找板失败".format("up")
                return res

            if max(leftBottom[1], rightBottom[1]) > (totalHeightMm - 30) * cp.mm2pix:
                res["result"] = "error"
                res["info"] = "{}框 找到的内板中缝,太靠近下边缘,判定找板失败".format("up")
                return res
            res["result"] = "ok"
            res["info"] = "识别成功!"
            return res
        else:
            res["result"] = "error"
            res["info"] = "识别的面积过大"
            res["calcSize"] = (totalWidthMm, totalHeightMm)
            res["calcError"] = (round(totalWidthMm - width / cp.mm2pix, 2), round(totalHeightMm - height / cp.mm2pix))
            return res
    except Exception as e:
        errorInfo = "in check_inner_board_first_check() error:{}".format(str(e))
        res["result"] = "error"
        res["info"] = errorInfo
        res["calcSize"] = (totalWidthMm, totalHeightMm)
        res["calcError"] = (round(totalWidthMm - width / cp.mm2pix, 2), round(totalHeightMm - height / cp.mm2pix, 2))
        return res


def get_new_box_for_no_middle(box, edgeNumber, extend):
    """
    根本板子的原来的位置信息,如果是上框,第一边,推测第三边中缝的位置.如果是下框,就是根据第三边推测第一边的位置.
    :param box:
    :param extend: 就是要延长的板的尺寸,这里一开始是使用高度进行延长
    :param boardPos:
    :return:
    """
    leftTop, rightTop, rightBottom, leftBottom = box
    if edgeNumber == "2":
        topK, topB = get_line_k_and_b(leftTop, rightTop)
        bottomK, bottomB = get_line_k_and_b(leftBottom, rightBottom)
        if topK == 0 or bottomK == 0:
            newRightTop = [int(leftTop[0] + extend), rightTop[1]]
            newRightBottom = [int(leftBottom[0] + extend), rightBottom[1]]
            newLeftTop = leftTop
            newLeftBottom = leftBottom
        else:
            xOffset = abs(extend * np.cos(trans_k_to_rad(topK)))  # 先将延长的距离,换算成x坐标的跨度.
            rightTopX = int(leftTop[0] + xOffset)
            rightTopY = int(topK * rightTopX + topB)
            rightBottomX = int(leftBottom[0] + xOffset)
            rightBottomY = int(bottomK * rightBottomX + bottomB)
            newRightTop = [rightTopX, rightTopY]
            newRightBottom = [rightBottomX, rightBottomY]
            newLeftTop = leftTop
            newLeftBottom = leftBottom
    elif edgeNumber == "3":
        leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
        rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
        if leftK is None or rightK is None:
            newLeftBottom = [leftTop[0], leftTop[1] + extend]
            newRightBottom = [rightTop[0], rightTop[1] + extend]
            newLeftTop = leftTop
            newRightTop = rightTop
        else:
            yOffset = abs(extend * np.sin(trans_k_to_rad(leftK)))
            leftBottomY = int(leftTop[1] + yOffset)
            leftBottomX = int((leftBottomY - leftB) / leftK)
            rightBottomY = int(rightTop[1] + yOffset)
            rightBottomX = int((rightBottomY - rightB) / rightK)
            newLeftBottom = [leftBottomX, leftBottomY]
            newRightBottom = [rightBottomX, rightBottomY]
            newLeftTop = leftTop
            newRightTop = rightTop
    elif edgeNumber == "1":
        leftK, leftB = get_line_k_and_b(leftTop, leftBottom)
        rightK, rightB = get_line_k_and_b(rightTop, rightBottom)
        if leftK is None or rightK is None:
            newLeftTop = [leftTop[0], leftBottom[1] - extend]
            newRightTop = [rightTop[0], rightBottom[1] - extend]
            newLeftBottom = leftBottom
            newRightBottom = rightBottom
        else:
            yOffset = abs(extend * np.sin(trans_k_to_rad(leftK)))
            leftTopY = int(leftBottom[1] - yOffset)
            leftTopX = int((leftTopY - leftB) / leftK)
            rightTopY = int(rightBottom[1] - yOffset)
            rightTopX = int((rightTopY - rightB) / rightK)
            newLeftTop = [leftTopX, leftTopY]
            newRightTop = [rightTopX, rightTopY]
            newLeftBottom = leftBottom
            newRightBottom = rightBottom
    else:
        topK, topB = get_line_k_and_b(leftTop, rightTop)
        bottomK, bottomB = get_line_k_and_b(leftBottom, rightBottom)
        if topK == 0 or bottomK == 0:
            newLeftTop = [int(rightTop[0] - extend), rightTop[1]]
            newLeftBottom = [int(rightBottom[0] - extend), rightBottom[1]]
            newRightTop = rightTop
            newRightBottom = rightBottom
        else:
            xOffset = abs(extend * np.cos(trans_k_to_rad(topK)))  # 先将延长的距离,换算成x坐标的跨度.
            leftTopX = int(rightTop[0] - xOffset)
            leftTopY = int(topK * leftTopX + topB)
            leftBottomX = int(rightBottom[0] - xOffset)
            leftBottomY = int(bottomK * leftBottomX + bottomB)
            newLeftTop = [leftTopX, leftTopY]
            newLeftBottom = [leftBottomX, leftBottomY]
            newRightTop = rightTop
            newRightBottom = rightBottom

    return [newLeftTop, newRightTop, newRightBottom, newLeftBottom]


def get_size_check_result_6p(image, width, height, calcThresBig, totalBoardBox, totalBoard):
    print("函数 get_size_check_result_6p() 被调用,获取尺寸确认的图片")
    if image is None:
        return "error", None, None, None

    jointLineMask1 = np.ones(image.shape, dtype=np.uint8) * 255
    # 竖着进板的填充
    jointLineMask1[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    # 横着进板的填充
    # jointLineMask1[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 0
    jointLineMaskNoAngle1, _ = get_board_without_angle(jointLineMask1, totalBoardBox)

    jointLineMask2 = np.zeros(image.shape, dtype=np.uint8)
    # 竖着进板的填充
    jointLineMask2[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 255
    # 横着进板的填充
    # jointLineMask2[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 255
    jointLineMaskNoAngle2, _ = get_board_without_angle(jointLineMask2, totalBoardBox)
    cv.destroyAllWindows()
    image_show("TotalBoard", totalBoard)

    w, h = totalBoardBox[1]
    heightHalf = int(h / 2)
    widthHalf = int(w / 2)
    upLeftBoard = totalBoard.copy()[:int(heightHalf + upDownSlice6p), :int(widthHalf + leftRightSlice6p)]
    upLeftBoardColor = cv.cvtColor(upLeftBoard, cv.COLOR_GRAY2BGR)
    jointLine1 = jointLineMaskNoAngle1.copy()[:int(heightHalf + upDownSlice6p), :int(widthHalf + leftRightSlice6p)]
    jointLine2 = jointLineMaskNoAngle2.copy()[:int(heightHalf + upDownSlice6p), :int(widthHalf + leftRightSlice6p)]

    upRes, upSizes, upBoxes = get_inner_board_for_size_check_6p(upLeftBoard, jointLine1, jointLine2, width, height, calcThresBig)
    upBoardResList = []
    upSizeResList = []
    if upRes != "error":
        for index, upBox in enumerate(upBoxes):
            if upBox is not None:
                upBoardRes = upLeftBoardColor.copy()
                cv.drawContours(upBoardRes, [np.array(upBox)], -1, colorGreen, 3)
                centerX, centerY = upLeftBoard.shape[1] // 2, upLeftBoard.shape[0] // 2
                cv.putText(upBoardRes, "{}".format(index + 1), (centerX - 8, centerY), cv.FONT_HERSHEY_COMPLEX, 10, colorBlue, 5)
                image_show("upBoardRes", upBoardRes)
                upBoardResList.append(upBoardRes)
                upSizeResList.append(upSizes[index])
        return "ok", upSizeResList, upBoardResList, upLeftBoardColor
    else:
        return "error", "内板识别出错", None, upLeftBoardColor


def get_boxes_6p(image, width, height, calcThresBig, calcThresSmall, totalBoardBox, totalBoard):
    jointLineMask1 = np.ones(image.shape, dtype=np.uint8) * 255
    # 竖着进板的填充
    jointLineMask1[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 0
    # 横着进板的填充
    # jointLineMask1[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 0
    jointLineMaskNoAngle1, _ = get_board_without_angle(jointLineMask1, totalBoardBox)

    jointLineMask2 = np.zeros(image.shape, dtype=np.uint8)
    # 竖着进板的填充
    jointLineMask2[:, cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend] = 255
    # 横着进板的填充
    # jointLineMask2[cp.middleJointPos - jointLineExtend:cp.middleJointPos + jointLineExtend, :] = 255
    jointLineMaskNoAngle2, _ = get_board_without_angle(jointLineMask2, totalBoardBox)
    totalBoardColor = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)

    image_show("TotalBoard", totalBoardColor)
    imageHeight, imageWidth = image.shape[:2]
    moveWidth = int(imageWidth * 0.2)
    moveHeight = int(imageHeight * 0.2)
    sizeOkRes = []
    sizeDifRes = []
    calcArgs = calcArgs6pin
    for tryTimes in range(tryBeginIndex, len(calcArgs.keys()) + 1):
        cv.destroyAllWindows()
        gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate = calcArgs.get(str(tryTimes))
        print("算法进行第{}次计算,计算参数:(高斯半径:{}),(方差核大小:{}),(膨胀腐蚀核:{}),(膨胀腐蚀次数:{}),(腐蚀膨胀次数:{})),(阈值offset:{}),(scharr比例:{})".format(
            tryTimes, gaussianR, squareR, dilateKernel, dilateTimes, erodeTimes, thresOffsetList, scharrRate))

        if len(gaussianR) == 1:
            if gaussianR[0] == 0:
                blurred = totalBoard.copy()
            else:
                blurred = cv.GaussianBlur(totalBoard, (0, 0), gaussianR[0])
        else:
            d, colorSigma = gaussianR
            spaceSigma = int(d / 2)
            blurred = cv.bilateralFilter(totalBoard, d, colorSigma, spaceSigma)
        if scharrRate == 0:
            scharrXY = blurred.copy()
        else:
            # 使用scharr核获取边缘
            scharrX = cv.Scharr(blurred, cv.CV_64F, 1, 0)
            scharrX = cv.convertScaleAbs(scharrX)
            scharrY = cv.Scharr(blurred, cv.CV_64F, 0, 1)
            scharrY = cv.convertScaleAbs(scharrY)
            scharrXY = cv.addWeighted(scharrX, scharrRate, scharrY, scharrRate, 0)
            scharrXY = cv.bitwise_and(scharrXY, jointLineMaskNoAngle1)
        image_show("ScharrXY", scharrXY, )

        # 求均方差
        img32 = np.float32(scharrXY)
        square1 = cv.blur(np.multiply(img32, img32), (squareR, squareR))
        square2 = np.multiply(cv.blur(img32, (squareR, squareR)), cv.blur(img32, (squareR, squareR)))
        squareDif32 = np.subtract(square1, square2)
        squareDif = squareDif32.copy()
        np.clip(squareDif32, 0, 255, out=squareDif)
        squareDif = squareDif.astype("uint8")
        image_show("SquareDif", squareDif)

        # 1.进行膨胀腐蚀,分割图像
        contourImg = squareDif.copy()
        kernelUsed = cv.getStructuringElement(cv.MORPH_RECT, (dilateKernel, dilateKernel))
        contourImg = cv.dilate(contourImg, kernelUsed, iterations=dilateTimes)
        contourImg = cv.erode(contourImg, kernelUsed, iterations=dilateTimes)

        squareDifDilateErode = contourImg.copy()
        # 2.根据阈值进行分割查找
        for index, thresOffset in enumerate(thresOffsetList):
            cv.destroyAllWindows()
            image_show("squareDifDilateErode", squareDifDilateErode)
            thresUsed = squareDifDilateErode[moveHeight:int(contourImg.shape[0] - moveHeight),
                        moveWidth:contourImg.shape[1] - moveWidth]
            print("使用第{}个阈值 thresOffset = {}".format(index + 1, thresOffset))
            if thresOffset != 0:
                _, contourImg = cv.threshold(squareDifDilateErode, thresOffset, 255, cv.THRESH_BINARY)
            else:
                _, contourImg = cv.threshold(squareDifDilateErode, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
            # 3.处理拼接处,并进行泛红填充
            mask = np.zeros((contourImg.shape[0] + 2, contourImg.shape[1] + 2), dtype="uint8")
            cv.floodFill(contourImg, mask, (contourImg.shape[1] // 4, contourImg.shape[0] // 6), 150)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] * 3 // 4, contourImg.shape[0] // 6), 150)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] // 4, contourImg.shape[0] // 2), 150)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] * 3 // 4, contourImg.shape[0] // 2), 150)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] // 4, contourImg.shape[0] * 5 // 6), 150)
            cv.floodFill(contourImg, mask, (contourImg.shape[1] * 3 // 4, contourImg.shape[0] * 5 // 6), 150)

            floodFill = np.zeros(contourImg.shape, dtype=np.uint8)
            floodFill[contourImg == 150] = 255
            image_show("FloodFill", floodFill)

            # 4.进行腐蚀膨胀,去除边界的噪声
            floodFill = cv.erode(floodFill, kernelUsed, iterations=erodeTimes)
            floodFill = cv.dilate(floodFill, kernelUsed, iterations=erodeTimes)
            image_show("FloodFillErodeDilate", floodFill)

            # 去掉四个角
            cv.rectangle(floodFill, (0, 0), (moveWidth, moveHeight), 0, -1)
            cv.rectangle(floodFill, (0, floodFill.shape[0]), (moveWidth, floodFill.shape[0] - moveHeight), 0, -1)
            cv.rectangle(floodFill, (floodFill.shape[1], 0), (floodFill.shape[1] - moveWidth, moveHeight), 0, -1)
            cv.rectangle(floodFill, (floodFill.shape[1], floodFill.shape[0]),
                         (floodFill.shape[1] - moveWidth, floodFill.shape[0] - moveHeight), 0, -1)
            image_show("MoveAngle", floodFill)

            res = check_inner_board_6(floodFill, width, height, calcThresBig, calcThresSmall, totalBoardColor)
            print("第{}次识别结果:{},识别信息:{},识别尺寸:{},识别误差:{}".format(
                tryTimes, res["result"], res["info"], res["calcSize"], res["calcError"]))
            if res["result"] == "ok":
                boxes = res["boxes"]
                showImage = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)

                for b in boxes:
                    cv.rectangle(showImage, tuple(b[0]), tuple(b[2]), (0, 255, 0), 5)
                image_show("SixBoxes", showImage)
                sizeOkRes.append(res)
                if int(np.sum(res["calcError"])) < 20:
                    print("返回的ok结果是,尺寸:{},{},误差:{}".format(res["calcSize"], (int(res["calcSize"][0] * cp.mm2pix)),
                                                                     int(res["calcSize"][1] * cp.mm2pix)), res["calcError"])
                    return True, "识别成功", res["boxes"]
                continue
            elif res["result"] != "error":
                sizeDifRes.append(res)
                continue
    else:
        if len(sizeOkRes) >= 1:
            resOkSorted = sorted(sizeOkRes, key=lambda x: np.sum(x["calcError"]))
            res = resOkSorted[0]
            print("返回的ok结果是,尺寸:{},{},误差:{}".format(res["calcSize"], (int(res["calcSize"][0] * cp.mm2pix),
                                                                               int(res["calcSize"][1] * cp.mm2pix)), res["calcError"]))
            return True, "识别成功", res["boxes"]
        else:
            return False, res["info"], None


def check_inner_board_6(boardMoveAngle, width, height, calcThresBig, calcThresSmall, boardColor):
    useImage = boardColor.copy()
    totalHeightPix, totalWidthPix = boardMoveAngle.shape[:2]
    boardArea = width * height
    totalWidthMm = round(totalWidthPix / cp.mm2pix, 2)
    totalHeightMm = round(totalHeightPix / cp.mm2pix, 2)
    res = {
        "result": "error",
        "box": None,
        "info": "",
        "calcSize": (totalWidthMm, totalHeightMm),
        "calcError": (0, 0),
    }

    cnts, _ = cv.findContours(boardMoveAngle.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
    cnts = sorted(cnts, key=cv.contourArea, reverse=True)
    s1 = 0
    s2 = 0
    s3 = 0
    s4 = 0
    s5 = 0
    s6 = 0
    if len(cnts) < 6:
        res["result"] = "error"
        res["info"] = "no six boxes"
        return res

    _, (w1, h1), _ = cv.minAreaRect(cnts[0])
    s1 = w1 * h1
    _, (w2, h2), _ = cv.minAreaRect(cnts[1])
    s2 = w2 * h2
    _, (w3, h3), _ = cv.minAreaRect(cnts[2])
    s3 = w3 * h3
    _, (w4, h4), _ = cv.minAreaRect(cnts[3])
    s4 = w4 * h4
    _, (w5, h5), _ = cv.minAreaRect(cnts[4])
    s5 = w5 * h5
    _, (w6, h6), _ = cv.minAreaRect(cnts[5])
    s6 = w6 * h6

    if 0.6 * boardArea < s1 < 1.6 * boardArea and 0.6 * boardArea < s2 < 1.6 * boardArea \
            and 0.6 * boardArea < s3 < 1.6 * boardArea and 0.6 * boardArea < s4 < 1.6 * boardArea \
            and 0.6 * boardArea < s5 < 1.6 * boardArea and 0.6 * boardArea < s6 < 1.6 * boardArea:
        res = check_box_6(cnts, width, height, calcThresBig, calcThresSmall)
        return res
    else:
        res["result"] = "error"
        res["info"] = "找板失败"
        return res


def check_box_6(cnts, board_w_pix, board_h_pix, calcThresBig, calcThresSmall):
    '''
    分析找出来的框是否满足要求
    输入：轮廓，长，宽
    输出：识别结果（ok/fail/error），ok的话还要返回上下框，与长宽的误差，是否重分割过，fail的话要返回原因
    '''
    assert len(cnts) >= 2

    res = {
        "result": "fail",
        "boxes": [],
        "info": "",
        "calcSize": (0, 0),
        "calcError": (0, 0)
    }
    start_id = 0
    try:
        # 长宽上下限
        w_min = board_w_pix - calcThresSmall * cp.mm2pix
        w_max = board_w_pix + calcThresBig * cp.mm2pix
        h_min = board_h_pix - calcThresSmall * cp.mm2pix
        h_max = board_h_pix + calcThresBig * cp.mm2pix

        boxes = [cv.minAreaRect(cnts[start_id + i]) for i in range(6)]

        # 求每个框中心点的x+y值，最小的是左上框，最大的是右下框，中间两框再判断
        box_xy = {}
        for index, item in enumerate(boxes):
            box_xy[index] = [item[0][0], item[0][1]]
        # 排序
        sorted_xy = sorted(box_xy.items(), key=lambda x: (x[1][0] + x[1][1]))

        lt_box = boxes[int(sorted_xy[0][0])]
        rb_box = boxes[int(sorted_xy[-1][0])]
        # 对剩下的几个的x重新排序
        sorted_x = sorted(sorted_xy[1:-1], key=lambda x: x[1][0])

        # left 左边的两个点，判断y，y小的是lm，另一个是lb
        if sorted_x[0][1][1] > sorted_x[1][1][1]:
            lm_box = boxes[int(sorted_x[1][0])]
            lb_box = boxes[int(sorted_x[0][0])]
        else:
            lm_box = boxes[int(sorted_x[0][0])]
            lb_box = boxes[int(sorted_x[1][0])]

        # right 左边的两个点，判断y，y小的是lm，另一个是lb
        if sorted_x[2][1][1] > sorted_x[3][1][1]:
            rm_box = boxes[int(sorted_x[2][0])]
            rt_box = boxes[int(sorted_x[3][0])]
        else:
            rm_box = boxes[int(sorted_x[3][0])]
            rt_box = boxes[int(sorted_x[2][0])]

        # 获取端点
        lt_boxm = np.int0(cv.boxPoints(lt_box))
        rt_boxm = np.int0(cv.boxPoints(rt_box))
        rb_boxm = np.int0(cv.boxPoints(rb_box))
        lb_boxm = np.int0(cv.boxPoints(lb_box))
        lm_boxm = np.int0(cv.boxPoints(lm_box))
        rm_boxm = np.int0(cv.boxPoints(rm_box))
        boxms = [lt_boxm, rt_boxm, rm_boxm, rb_boxm, lb_boxm, lm_boxm]

        # 端点排序
        sorted_boxms = [get_rect_points_clockwise(boxm) for boxm in boxms]

        # 求宽度,高度
        widthes = [get_two_point_distance(boxm[0], boxm[1]) for boxm in sorted_boxms]
        heightes = [get_two_point_distance(boxm[0], boxm[3]) for boxm in sorted_boxms]

        res["calcSize"] = (int(sum(widthes) / 6 / cp.mm2pix), int(sum(heightes) / 6 / cp.mm2pix))
        widthError = [int((width - board_w_pix) / cp.mm2pix) for width in widthes]
        heightError = [int((height - board_h_pix) / cp.mm2pix) for height in heightes]
        res["calcError"] = [(errorSize[0], errorSize[1]) for errorSize in zip(widthError, heightError)]

        print("box list: lt, rt, rm, rb, lb,lm")
        print("width", widthes)
        print("height", heightes)

        if max(widthes) > w_max:
            res["result"] = "fail"
            res["info"] = "识别尺寸过大，小板过宽，识别结果 %.2f 毫米，阈值 %.2f 毫米，比阈值小 %.2f 毫米，请确定尺寸后重试！" % (
                max(widthes) / cp.mm2pix, w_max / cp.mm2pix, abs(max(widthes) - w_max) / cp.mm2pix)
            return res
        elif min(widthes) < w_min:
            res["result"] = "fail"
            res["info"] = "识别尺寸过小，小板过窄，识别结果 %.2f 毫米，阈值 %.2f 毫米，比阈值小 %.2f 毫米，请确定尺寸后重试！" % (
                min(widthes) / cp.mm2pix, w_min / cp.mm2pix, abs(min(widthes) - w_min) / cp.mm2pix)
            return res
        elif max(heightes) > h_max:
            res["result"] = "fail"
            res["info"] = "识别尺寸过大，小板过高，识别结果 %.2f 毫米，阈值 %.2f 毫米，比阈值小 %.2f 毫米，请确定尺寸后重试！" % (
                min(heightes) / cp.mm2pix, h_max / cp.mm2pix, abs(max(heightes) - h_max) / cp.mm2pix)
            return res
        elif min(heightes) < h_min:
            res["result"] = "fail"
            res["info"] = "识别尺寸过小，小板过矮，识别结果 %.2f 毫米，阈值 %.2f 毫米，比阈值小 %.2f 毫米，请确定尺寸后重试！" % (
                min(heightes) / cp.mm2pix, h_min / cp.mm2pix, abs(min(heightes) - h_min) / cp.mm2pix)
            return res
        # 如果板之间有重叠
        # boxm = p_lb,p_lt,p_rt,p_rb
        boxms_copy = boxms.copy()
        for boxm_0 in boxms:
            boxms_copy.remove(boxm_0)
            for boxm_1 in boxms_copy:
                if check_two_box_is_overlap(boxm_0, boxm_1):
                    res["result"] = "fail"
                    res["info"] = "识别板重叠"

        res["result"] = "ok"
        res["info"] = ""

        res["boxes"] = sorted_boxms

        return res

    except Exception as e:
        res["result"] = "error"
        res["info"] = str(e)
        return res


def get_lines_with_boxes_6p(image, boxList6p, transMtx, topRemain, leftRemain, bottomRemain, rightRemain, totalBoardBox, totalBoard,
                            totalBoardThres, totalBoardOffset):
    lt_box, rt_box, rm_box, rb_box, lb_box, lm_box = boxList6p
    lt_lt, lt_rt, lt_rb, lt_lb = lt_box
    rt_lt, rt_rt, rt_rb, rt_lb = rt_box
    rm_lt, rm_rt, rm_rb, rm_lb = rm_box
    rb_lt, rb_rt, rb_rb, rb_lb = rb_box
    lb_lt, lb_rt, lb_rb, lb_lb = lb_box
    lm_lt, lm_rt, lm_rb, lm_lb = lm_box
    # cut_remain_pix_acbd如果不等于-1，则证明需要切割ac，bd边，那就需要进行下面的计算

    left_cut_line_k = get_line_k_and_b(lt_lt, lb_lb)[0]
    # 直接分别求过四个点的直线的b参数，找出最值
    if left_cut_line_k is None:
        left_cut_line_b = min(lt_lt[0], lt_lb[0], lb_lt[0], lb_lb[0], lm_lt[0], lm_lb[0]) - leftRemain
    else:
        b_up_lt = lt_lt[1] - (lt_lt[0] - leftRemain) * left_cut_line_k
        b_up_lb = lt_lb[1] - (lt_lb[0] - leftRemain) * left_cut_line_k
        b_down_lt = lb_lt[1] - (lb_lt[0] - leftRemain) * left_cut_line_k
        b_down_lb = lb_lb[1] - (lb_lb[0] - leftRemain) * left_cut_line_k
        b_middle_lt = lm_lt[1] - (lm_lt[0] - leftRemain) * left_cut_line_k
        b_middle_lb = lm_lb[1] - (lm_lb[0] - leftRemain) * left_cut_line_k
        if left_cut_line_k > 0:  # 当k大于0时，b越大，越靠左
            left_cut_line_b = max(b_up_lt, b_up_lb, b_down_lt, b_down_lb, b_middle_lt, b_middle_lb)
        else:  # 当k小于0时，b越小，越靠左
            left_cut_line_b = min(b_up_lt, b_up_lb, b_down_lt, b_down_lb, b_middle_lt, b_middle_lb)

    right_cut_line_k = get_line_k_and_b(rt_rt, rb_rb)[0]
    # 直接分别求过四个点的直线的b参数，找出最值
    if right_cut_line_k is None:
        right_cut_line_b = max(rt_rt[0], rt_rb[0], rb_rt[0], rb_rb[0], rm_rt[0], rm_rb[0]) + rightRemain
    else:
        b_up_rt = rt_rt[1] - (rt_rt[0] + rightRemain) * right_cut_line_k
        b_up_rb = rt_rb[1] - (rt_rb[0] + rightRemain) * right_cut_line_k
        b_down_rt = rb_rt[1] - (rb_rt[0] + rightRemain) * right_cut_line_k
        b_down_rb = rb_rb[1] - (rb_rb[0] + rightRemain) * right_cut_line_k
        b_middle_rt = rm_rt[1] - (rm_rt[0] + rightRemain) * right_cut_line_k
        b_middle_rb = rm_rb[1] - (rm_rb[0] + rightRemain) * right_cut_line_k
        if right_cut_line_k > 0:  # 当k大于0时，b越大，越靠左
            right_cut_line_b = min(b_up_rt, b_up_rb, b_down_rt, b_down_rb, b_middle_rt, b_middle_rb)
        else:  # 当k小于0时，b越小，越靠左
            right_cut_line_b = max(b_up_rt, b_up_rb, b_down_rt, b_down_rb, b_middle_rt, b_middle_rb)

    top_cut_line_k = get_line_k_and_b(lt_lt, rt_rt)[0]
    # 直接分别求过四个点的直线的b参数，找出最值
    if top_cut_line_k is None:
        return "error", None, None, None, None, None, None, None, None
    else:
        b_left_lt = lt_lt[1] - topRemain - lt_lt[0] * top_cut_line_k
        b_left_rt = lt_rt[1] - topRemain - lt_rt[0] * top_cut_line_k
        b_right_lt = rt_lt[1] - topRemain - rt_lt[0] * top_cut_line_k
        b_right_rt = rt_rt[1] - topRemain - rt_rt[0] * top_cut_line_k

        # if top_cut_line_k > 0:  # 当k大于0时，b越大，越靠左
        #     top_cut_line_b = max(b_left_lt, b_left_rt, b_right_lt, b_right_rt)
        # else:  # 当k小于0时，b越小，越靠左
        top_cut_line_b = min(b_left_lt, b_left_rt, b_right_lt, b_right_rt)

    bottom_cut_line_k = get_line_k_and_b(lb_lb, rb_rb)[0]
    # 直接分别求过四个点的直线的b参数，找出最值
    if bottom_cut_line_k is None:
        return "error", None, None, None, None, None, None, None, None
    else:
        b_left_lt = lb_lb[1] + bottomRemain - lb_lb[0] * bottom_cut_line_k
        b_left_rt = lb_rb[1] + bottomRemain - lb_rb[0] * bottom_cut_line_k
        b_right_lt = rb_lb[1] + bottomRemain - rb_lb[0] * bottom_cut_line_k
        b_right_rt = rb_rb[1] + bottomRemain - rb_rb[0] * bottom_cut_line_k

        # if bottom_cut_line_k < 0:  # 当k大于0时，b越大，越靠左
        bottom_cut_line_b = max(b_left_lt, b_left_rt, b_right_lt, b_right_rt)
        # else:  # 当k小于0时，b越小，越靠左
        #     bottom_cut_line_b = min(b_left_lt, b_left_rt, b_right_lt, b_right_rt)

    # 求水平方向中线
    horizontal_middle_up_line = calc_middle_line(np.array([lt_lb, lt_rb, rt_lb, rt_rb]).tolist(),
                                                 np.array([lm_lt, lm_rt, rm_lt, rm_rt]).tolist())
    horizontal_middle_down_line = calc_middle_line(np.array([lm_lb, lm_rb, rm_lb, rm_rb]).tolist(),
                                                   np.array([lb_lt, lb_rt, rb_lt, rb_rt]).tolist())
    middleUpIsOk = True  # 上面的中缝是否正确
    middleDownIsOk = True  # 下面的中缝是否正确

    if horizontal_middle_up_line[0] is None:
        middleUpIsOk = False
        horizontal_middle_up_line = get_horizontal_middle_line_4p([lt_lb, lt_rb, rt_lb, rt_rb],
                                                                  [lm_lt, lm_rt, rm_lt, rm_rt])
    if horizontal_middle_down_line[0] is None:
        middleDownIsOk = False
        horizontal_middle_down_line = get_horizontal_middle_line_4p([lm_lb, lm_rb, rm_lb, rm_rb],
                                                                    [lb_lt, lb_rt, rb_lt, rb_rt])

    horizontal_middle_up_line, horizontal_middle_down_line = get_horizontal_middle_line(horizontal_middle_up_line,
                                                                                        horizontal_middle_down_line,
                                                                                        (lt_lb[0] + rt_rb[0]) // 2)

    # 求竖直方向中线
    vertical_middle_line = calc_middle_line(np.array([lt_rt, lt_rb, lb_rt, lb_rb]).tolist(),
                                            np.array([rt_lt, rt_lb, rb_lt, rb_lb]).tolist())

    # 求竖直方向的中线,求三条,分开求
    vertical_middle_line_1 = get_vertical_middle_cut_line((lt_rt, lt_rb), (rt_lt, rt_lb))
    vertical_middle_line_2 = get_vertical_middle_cut_line((lm_rt, lm_rb), (rm_lt, rm_lb))
    vertical_middle_line_3 = get_vertical_middle_cut_line((lb_rt, lb_rb), (rb_lt, rb_lb))
    # vertical_middle_line = calc_middle_line.calc_middle_line(np.array([lt_rt,lt_rb]).tolist(),np.array([rt_lt,rt_lb]).tolist())

    if horizontal_middle_down_line[0] is None or horizontal_middle_up_line[0] is None or \
            vertical_middle_line_1[1] is None or vertical_middle_line_2[1] is None or vertical_middle_line_3[1] is None:
        print("水平中线1: {},水平中线2: {},垂直中线1: {},垂直中线2: {},垂直中线3: {}".format(
            horizontal_middle_up_line, horizontal_middle_down_line, vertical_middle_line_1,
            vertical_middle_line_2, vertical_middle_line_3))
        return "中线获取失败", [], None, None, None, None, None, None, None

    rotatedCenter, (w, h), rotatedAngle = totalBoardBox
    boardLeftTop = [0, 0]
    boardRightTop = [w, 0]
    boardRightBottom = [w, h]
    boardLeftBottom = [0, h]
    findEdgeExtend = int(7 * cp.mm2pix)
    totalBoardExtendForFindEdge, _ = get_board_without_angle(image, totalBoardBox, findEdgeExtend)
    totalBoardThresForFindEdge, _ = get_board_without_angle(totalBoardThres, totalBoardBox, findEdgeExtend)
    # 考虑到留边宽度是0的时候,分别计算四条边线的斜率和b值
    if topRemain == 0:
        topLineK, topLineB = find_first_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend)
        if topLineK is None:
            top_cut_line_k, top_cut_line_b = get_line_k_and_b((0, 0), (w, 0))
        else:
            top_cut_line_k, top_cut_line_b = topLineK, topLineB
    if bottomRemain == 0:
        bottomLineK, bottomLineB = find_third_edge_line(totalBoardExtendForFindEdge, totalBoardThresForFindEdge, findEdgeExtend)
        if bottomLineK is None:
            bottom_cut_line_k, bottom_cut_line_b = get_line_k_and_b((0, h), (w, h))
        else:
            bottom_cut_line_k, bottom_cut_line_b = bottomLineK, bottomLineB
    if leftRemain == 0:
        left_cut_line_k, left_cut_line_b = get_line_k_and_b((0, 0), (0, h))
    if rightRemain == 0:
        right_cut_line_k, right_cut_line_b = get_line_k_and_b((w, 0), (w, h))

    # ①求所有的交点，当上下左右四条边都切时

    left_top_cross = get_two_lines_intersection(top_cut_line_k, top_cut_line_b, left_cut_line_k, left_cut_line_b)
    right_top_cross = get_two_lines_intersection(top_cut_line_k, top_cut_line_b, right_cut_line_k, right_cut_line_b)
    left_bottom_cross = get_two_lines_intersection(bottom_cut_line_k, bottom_cut_line_b, left_cut_line_k, left_cut_line_b)
    right_bottom_cross = get_two_lines_intersection(bottom_cut_line_k, bottom_cut_line_b, right_cut_line_k, right_cut_line_b)

    if left_top_cross[0] is None or right_top_cross[0] is None or left_bottom_cross[0] is None or \
            right_bottom_cross[0] is None:
        # cv.destroyAllWindows()
        return "error", None, None, None, None, None, None, None, None
    extend13 = int(8 * cp.mm2pix)  # 1,3刀的延长线
    extend24 = int(18 * cp.mm2pix)  # 2,4刀的延长线

    top_cut_in_point = [- extend13, top_cut_line_k * (- extend13) + top_cut_line_b]
    top_cut_out_point = [extend13 + w, top_cut_line_k * (extend13 + w) + top_cut_line_b]

    # bottom_cut_in_point = [w + 10,
    #                        bottom_cut_line_k * (w + 10) + bottom_cut_line_b]
    bottom_cut_in_point = [w + extend13,
                           bottom_cut_line_k * (w + extend13) + bottom_cut_line_b]
    bottom_cut_out_point = [left_bottom_cross[0] - extend13, bottom_cut_line_k * (left_bottom_cross[0] - extend13) + bottom_cut_line_b]

    if left_cut_line_k is None:
        left_cut_in_point = [left_cut_line_b, left_bottom_cross[1] + extend24]
        # left_cut_out_point = [left_cut_line_b, -5]
        left_cut_out_point = [left_cut_line_b, left_top_cross[1] - extend24]
    elif left_cut_line_k != 0:
        left_cut_in_point = [((left_bottom_cross[1] + extend24) - left_cut_line_b) / left_cut_line_k,
                             left_bottom_cross[1] + extend24]
        left_cut_out_point = [(left_top_cross[1] - extend24 - left_cut_line_b) / left_cut_line_k, left_top_cross[1] - extend24]
    else:
        cv.destroyAllWindows()
        return "error", None, None, None, None, None, None, None, None, None

    if right_cut_line_k is None:
        right_cut_in_point = [right_cut_line_b, right_top_cross[1] - extend24]
        right_cut_out_point = [right_cut_line_b, right_bottom_cross[1] + extend24]
    elif right_cut_line_k != 0:
        right_cut_in_point = [((right_top_cross[1] - extend24) - right_cut_line_b) / right_cut_line_k,
                              right_top_cross[1] - extend24]
        right_cut_out_point = [((right_bottom_cross[1] + extend24) - right_cut_line_b) / right_cut_line_k,
                               right_bottom_cross[1] + extend24]
    else:
        cv.destroyAllWindows()
        return "error", None, None, None, None, None, None, None, None, None

    left_middle_up_cross = get_two_lines_intersection(horizontal_middle_up_line[0], horizontal_middle_up_line[1], left_cut_line_k,
                                                      left_cut_line_b)
    right_middle_up_cross = get_two_lines_intersection(horizontal_middle_up_line[0], horizontal_middle_up_line[1], right_cut_line_k,
                                                       right_cut_line_b)

    horizontal_middle_up_cut_in_point = [left_middle_up_cross[0] - extend13,
                                         (left_middle_up_cross[0] - extend13) * horizontal_middle_up_line[0] +
                                         horizontal_middle_up_line[1]]
    horizontal_middle_up_cut_out_point = [right_middle_up_cross[0] + extend13,
                                          (right_middle_up_cross[0] + extend13) * horizontal_middle_up_line[0] +
                                          horizontal_middle_up_line[1]]

    # 求水平中线与左右线的交点,如果k为None一定有问题
    if horizontal_middle_down_line[0] is None:
        return "error", None, None, None, None, None, None, None, None, None, None
    left_middle_down_cross = get_two_lines_intersection(horizontal_middle_down_line[0], horizontal_middle_down_line[1], left_cut_line_k,
                                                        left_cut_line_b)
    right_middle_down_cross = get_two_lines_intersection(horizontal_middle_down_line[0], horizontal_middle_down_line[1], right_cut_line_k,
                                                         right_cut_line_b)

    horizontal_middle_down_cut_in_point = [left_middle_down_cross[0] - extend13,
                                           (left_middle_down_cross[0] - extend13) * horizontal_middle_down_line[0] +
                                           horizontal_middle_down_line[1]]
    horizontal_middle_down_cut_out_point = [right_middle_down_cross[0] + extend13,
                                            (right_middle_down_cross[0] + extend13) * horizontal_middle_down_line[0] +
                                            horizontal_middle_down_line[1]]

    dis_board = cv.cvtColor(totalBoard, cv.COLOR_GRAY2BGR)
    k1, b1 = vertical_middle_line_1
    if vertical_middle_line_1[0] is None:
        vertical_middle_cut_in_point1 = [b1, 0]
        vertical_middle_cut_out_point1 = get_two_lines_intersection(k1, b1, horizontal_middle_up_line[0], horizontal_middle_up_line[1])
    else:

        vertical_middle_cut_in_point1 = [-1 * b1 / k1, 0]
        vertical_middle_cut_out_point1 = get_two_lines_intersection(k1, b1, horizontal_middle_up_line[0], horizontal_middle_up_line[1])

    k2, b2 = vertical_middle_line_2
    if vertical_middle_line_2[0] is None:
        vertical_middle_cut_in_point2 = get_two_lines_intersection(k2, b2, horizontal_middle_up_line[0], horizontal_middle_up_line[1])
        vertical_middle_cut_out_point2 = get_two_lines_intersection(k2, b2, horizontal_middle_down_line[0], horizontal_middle_down_line[1])
    else:

        vertical_middle_cut_in_point2 = get_two_lines_intersection(k2, b2, horizontal_middle_up_line[0], horizontal_middle_up_line[1])
        vertical_middle_cut_out_point2 = get_two_lines_intersection(k2, b2, horizontal_middle_down_line[0], horizontal_middle_down_line[1])

    k3, b3 = vertical_middle_line_3
    if vertical_middle_line_3[0] is None:
        vertical_middle_cut_in_point3 = get_two_lines_intersection(k3, b3, horizontal_middle_down_line[0], horizontal_middle_down_line[1])
        vertical_middle_cut_out_point3 = [b3, dis_board.shape[0]]
    else:

        vertical_middle_cut_in_point3 = get_two_lines_intersection(k3, b3, horizontal_middle_down_line[0], horizontal_middle_down_line[1])
        vertical_middle_cut_out_point3 = [(dis_board.shape[0] - b3) / k3, dis_board.shape[0]]

    M = cv.getRotationMatrix2D(rotatedCenter, -rotatedAngle, 1)
    centerOffset = totalBoardOffset

    boardLeftTopBig = np.dot(M, [boardLeftTop[0] + centerOffset[0], boardLeftTop[1] + centerOffset[1], 1])
    boardRightTopBig = np.dot(M, [boardRightTop[0] + centerOffset[0], boardRightTop[1] + centerOffset[1], 1])
    boardRightBottomBig = np.dot(M, [boardRightBottom[0] + centerOffset[0], boardRightBottom[1] + centerOffset[1], 1])
    boardLeftBottomBig = np.dot(M, [boardLeftBottom[0] + centerOffset[0], boardLeftBottom[1] + centerOffset[1], 1])

    top_cut_in_point_b = np.dot(M, [top_cut_in_point[0] + centerOffset[0], top_cut_in_point[1] + centerOffset[1], 1])
    top_cut_out_point_b = np.dot(M, [top_cut_out_point[0] + centerOffset[0], top_cut_out_point[1] + centerOffset[1], 1])
    bottom_cut_in_point_b = np.dot(M, [bottom_cut_in_point[0] + centerOffset[0], bottom_cut_in_point[1] + centerOffset[1], 1])
    bottom_cut_out_point_b = np.dot(M, [bottom_cut_out_point[0] + centerOffset[0], bottom_cut_out_point[1] + centerOffset[1], 1])

    left_cut_in_point_b = np.dot(M, [left_cut_in_point[0] + centerOffset[0], left_cut_in_point[1] + centerOffset[1], 1])
    left_cut_out_point_b = np.dot(M, [left_cut_out_point[0] + centerOffset[0], left_cut_out_point[1] + centerOffset[1], 1])
    right_cut_in_point_b = np.dot(M, [right_cut_in_point[0] + centerOffset[0], right_cut_in_point[1] + centerOffset[1], 1])
    right_cut_out_point_b = np.dot(M, [right_cut_out_point[0] + centerOffset[0], right_cut_out_point[1] + centerOffset[1], 1])
    vertical_middle_cut_in_point_b_1 = np.dot(M, [vertical_middle_cut_in_point1[0] + centerOffset[0],
                                                  vertical_middle_cut_in_point1[1] + centerOffset[1], 1])
    vertical_middle_cut_out_point_b_1 = np.dot(M, [vertical_middle_cut_out_point1[0] + centerOffset[0],
                                                   vertical_middle_cut_out_point1[1] + centerOffset[1], 1])
    vertical_middle_cut_in_point_b_2 = np.dot(M, [vertical_middle_cut_in_point2[0] + centerOffset[0],
                                                  vertical_middle_cut_in_point2[1] + centerOffset[1], 1])
    vertical_middle_cut_out_point_b_2 = np.dot(M, [vertical_middle_cut_out_point2[0] + centerOffset[0],
                                                   vertical_middle_cut_out_point2[1] + centerOffset[1], 1])
    vertical_middle_cut_in_point_b_3 = np.dot(M, [vertical_middle_cut_in_point3[0] + centerOffset[0],
                                                  vertical_middle_cut_in_point3[1] + centerOffset[1], 1])
    vertical_middle_cut_out_point_b_3 = np.dot(M, [vertical_middle_cut_out_point3[0] + centerOffset[0],
                                                   vertical_middle_cut_out_point3[1] + centerOffset[1], 1])
    horizontal_middle_up_cut_in_point_b = np.dot(M, [horizontal_middle_up_cut_in_point[0] + centerOffset[0],
                                                     horizontal_middle_up_cut_in_point[1] + centerOffset[1], 1])
    horizontal_middle_up_cut_out_point_b = np.dot(M, [horizontal_middle_up_cut_out_point[0] + centerOffset[0],
                                                      horizontal_middle_up_cut_out_point[1] + centerOffset[1], 1])
    horizontal_middle_down_cut_in_point_b = np.dot(M, [horizontal_middle_down_cut_in_point[0] + centerOffset[0],
                                                       horizontal_middle_down_cut_in_point[1] + centerOffset[1], 1])
    horizontal_middle_down_cut_out_point_b = np.dot(M, [horizontal_middle_down_cut_out_point[0] + centerOffset[0],
                                                        horizontal_middle_down_cut_out_point[1] + centerOffset[1], 1])

    # 重新将端点定位到大图上去
    points = [lt_lt, lt_rt, lt_rb, lt_lb,
              rt_lt, rt_rt, rt_rb, rt_lb,
              rb_lt, rb_rt, rb_rb, rb_lb,
              lb_lt, lb_rt, lb_rb, lb_lb,
              rm_lt, rm_rt, rm_rb, rm_lb,
              lm_lt, lm_rt, lm_rb, lm_lb,
              ]
    imageColor = cv.cvtColor(image, cv.COLOR_GRAY2BGR)
    points_real = [np.dot(M, [p[0] + centerOffset[0], p[1] + centerOffset[1], 1]) for p in points]

    box1 = points_real[:4]
    box2 = points_real[4:8]
    box3 = points_real[8:12]
    box4 = points_real[12:16]
    box5 = points_real[16:20]
    box6 = points_real[20:24]

    for index, p in enumerate(box1):
        p1 = (int(p[0]), int(p[1]))
        p2 = box1[(index + 1) % len(box1)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    for index, p in enumerate(box2):
        p1 = (int(p[0]), int(p[1]))
        p2 = box2[(index + 1) % len(box2)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    for index, p in enumerate(box3):
        p1 = (int(p[0]), int(p[1]))
        p2 = box3[(index + 1) % len(box3)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    for index, p in enumerate(box4):
        p1 = (int(p[0]), int(p[1]))
        p2 = box4[(index + 1) % len(box4)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    for index, p in enumerate(box5):
        p1 = (int(p[0]), int(p[1]))
        p2 = box5[(index + 1) % len(box5)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    for index, p in enumerate(box6):
        p1 = (int(p[0]), int(p[1]))
        p2 = box6[(index + 1) % len(box6)]
        p2 = int(p2[0]), int(p2[1])
        cv.line(imageColor, p1, p2, (0, 0, 255), 3)

    # 画出上，下，左，右，中五条切线
    cv.line(imageColor, (int(top_cut_in_point_b[0]), int(top_cut_in_point_b[1])),
            (int(top_cut_out_point_b[0]), int(top_cut_out_point_b[1])), (0, 255, 0), 3)
    cv.putText(imageColor, '1', (int((top_cut_in_point_b[0] + top_cut_out_point_b[0]) / 2),
                                 int((top_cut_in_point_b[1] + top_cut_out_point_b[1]) / 2) - 60), cv.FONT_HERSHEY_COMPLEX, 4,
               (255, 0, 0), 12)
    cv.line(imageColor, (int(bottom_cut_in_point_b[0]), int(bottom_cut_in_point_b[1])),
            (int(bottom_cut_out_point_b[0]), int(bottom_cut_out_point_b[1])), (0, 255, 0), 3)
    cv.putText(imageColor, '3', (int((bottom_cut_in_point_b[0] + bottom_cut_out_point_b[0]) / 2),
                                 int((bottom_cut_in_point_b[1] + bottom_cut_out_point_b[1]) / 2) + 140), cv.FONT_HERSHEY_COMPLEX,
               4, (255, 0, 0), 12)
    cv.line(imageColor, (int(left_cut_in_point_b[0]), int(left_cut_in_point_b[1])),
            (int(left_cut_out_point_b[0]), int(left_cut_out_point_b[1])), (255, 0, 0), 3)
    cv.putText(imageColor, '2', (int((left_cut_in_point_b[0] + left_cut_out_point_b[0]) / 2) - 110,
                                 int((left_cut_in_point_b[1] + left_cut_out_point_b[1]) / 2)), cv.FONT_HERSHEY_COMPLEX,
               4, (255, 0, 0), 12)
    cv.line(imageColor, (int(right_cut_in_point_b[0]), int(right_cut_in_point_b[1])),
            (int(right_cut_out_point_b[0]), int(right_cut_out_point_b[1])), (255, 0, 0), 3)
    cv.putText(imageColor, '4', (int((right_cut_in_point_b[0] + right_cut_out_point_b[0]) / 2) + 30,
                                 int((right_cut_in_point_b[1] + right_cut_out_point_b[1]) / 2)), cv.FONT_HERSHEY_COMPLEX,
               4, (255, 0, 0), 12)
    cv.line(imageColor, (int(horizontal_middle_up_cut_in_point_b[0]), int(horizontal_middle_up_cut_in_point_b[1])),
            (int(horizontal_middle_up_cut_out_point_b[0]), int(horizontal_middle_up_cut_out_point_b[1])), (0, 255, 0), 3)
    cv.line(imageColor, (int(horizontal_middle_down_cut_in_point_b[0]), int(horizontal_middle_down_cut_in_point_b[1])),
            (int(horizontal_middle_down_cut_out_point_b[0]), int(horizontal_middle_down_cut_out_point_b[1])), (0, 255, 0), 3)
    cv.line(imageColor, (int(vertical_middle_cut_in_point_b_1[0]), int(vertical_middle_cut_in_point_b_1[1])),
            (int(vertical_middle_cut_out_point_b_1[0]), int(vertical_middle_cut_out_point_b_1[1])), (0, 255, 0), 3)

    cv.line(imageColor, (int(vertical_middle_cut_in_point_b_2[0]), int(vertical_middle_cut_in_point_b_2[1])),
            (int(vertical_middle_cut_out_point_b_2[0]), int(vertical_middle_cut_out_point_b_2[1])), (0, 255, 0), 3)
    cv.line(imageColor, (int(vertical_middle_cut_in_point_b_3[0]), int(vertical_middle_cut_in_point_b_3[1])),
            (int(vertical_middle_cut_out_point_b_3[0]), int(vertical_middle_cut_out_point_b_3[1])), (0, 255, 0), 3)
    # 显示出切线效果图，如果执行的是首板操作的话，还需要将首板的效果图保存下来

    # if is_frist_board:

    # else:
    #     cv.imwrite("./result_image/{}{}.bmp".format(image_name, image_node), imageColor)
    # cv.destroyAllWindows()

    # 综合10个点的信息
    top_cut_in_point_r = pix_pos_to_robot(top_cut_in_point_b, transMtx)
    top_cut_out_point_r = pix_pos_to_robot(top_cut_out_point_b, transMtx)
    bottom_cut_out_point_r = pix_pos_to_robot(bottom_cut_out_point_b, transMtx)
    bottom_cut_in_point_r = pix_pos_to_robot(bottom_cut_in_point_b, transMtx)
    left_cut_in_point_r = pix_pos_to_robot(left_cut_in_point_b, transMtx)
    left_cut_out_point_r = pix_pos_to_robot(left_cut_out_point_b, transMtx)
    right_cut_in_point_r = pix_pos_to_robot(right_cut_in_point_b, transMtx)
    right_cut_out_point_r = pix_pos_to_robot(right_cut_out_point_b, transMtx)
    vertical_middle_cut_in_point_r_1 = pix_pos_to_robot(vertical_middle_cut_in_point_b_1, transMtx)
    vertical_middle_cut_out_point_r_1 = pix_pos_to_robot(vertical_middle_cut_out_point_b_1, transMtx)
    vertical_middle_cut_in_point_r_2 = pix_pos_to_robot(vertical_middle_cut_in_point_b_2, transMtx)
    vertical_middle_cut_out_point_r_2 = pix_pos_to_robot(vertical_middle_cut_out_point_b_2, transMtx)
    vertical_middle_cut_in_point_r_3 = pix_pos_to_robot(vertical_middle_cut_in_point_b_3, transMtx)
    vertical_middle_cut_out_point_r_3 = pix_pos_to_robot(vertical_middle_cut_out_point_b_3, transMtx)

    horizontal_middle_up_cut_in_point_r = pix_pos_to_robot(horizontal_middle_up_cut_in_point_b, transMtx)
    horizontal_middle_up_cut_out_point_r = pix_pos_to_robot(horizontal_middle_up_cut_out_point_b, transMtx)
    horizontal_middle_down_cut_in_point_r = pix_pos_to_robot(horizontal_middle_down_cut_in_point_b, transMtx)
    horizontal_middle_down_cut_out_point_r = pix_pos_to_robot(horizontal_middle_down_cut_out_point_b, transMtx)

    boardLeftTopRobot = pix_pos_to_robot(boardLeftTopBig, transMtx)
    boardRightTopRobot = pix_pos_to_robot(boardRightTopBig, transMtx)
    boardRightBottomRobot = pix_pos_to_robot(boardRightBottomBig, transMtx)
    boardLeftBottomRobot = pix_pos_to_robot(boardLeftBottomBig, transMtx)

    result_image, _ = get_board_without_angle(imageColor, totalBoardBox, extend=80)
    # cv.imwrite("d:/result_image/%s.jpg" % (time.strftime('%Y-%m-%d_%H-%M-%S',time.localtime())), result_image)
    image_show("result_image", imageColor)

    firstBoardLenBig, secondBoardLenBig, thirdBoardLenBig, firstBoardLenSmall, secondBoardLenSmall, \
        thirdBoardLenSmall, forthBoardLenSmall, fifthBoardLenSmall, sixthBoardLenSmall = get_board_length_6(
        [top_cut_in_point_r, top_cut_out_point_r],
        [horizontal_middle_up_cut_in_point_r,
         horizontal_middle_up_cut_out_point_r],
        [bottom_cut_out_point_r, bottom_cut_in_point_r],
        [left_cut_out_point_r, left_cut_in_point_r],
        [vertical_middle_cut_in_point_r_1,
         vertical_middle_cut_out_point_r_1],
        [right_cut_in_point_r, right_cut_out_point_r],
        [horizontal_middle_down_cut_in_point_r,
         horizontal_middle_down_cut_out_point_r],
        [vertical_middle_cut_in_point_r_2,
         vertical_middle_cut_out_point_r_2],
        [vertical_middle_cut_in_point_r_3,
         vertical_middle_cut_out_point_r_3],
        618, 310)

    top_middle_angle = get_two_line_angle_6pin(horizontal_middle_up_cut_out_point_r, horizontal_middle_up_cut_in_point_r,
                                               top_cut_out_point_r, top_cut_in_point_r)  # 根据向量获取第一和第三刀的角度
    bottom_middle_angle = get_two_line_angle_6pin(horizontal_middle_up_cut_out_point_r, horizontal_middle_up_cut_in_point_r,
                                                  bottom_cut_in_point_r, bottom_cut_out_point_r)
    bottom_downmiddle_angle = get_two_line_angle_6pin(horizontal_middle_down_cut_out_point_r,
                                                      horizontal_middle_down_cut_in_point_r, bottom_cut_in_point_r,
                                                      bottom_cut_out_point_r)
    right_middle_angle_1 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_1,
                                                   vertical_middle_cut_in_point_r_1, right_cut_out_point_r, right_cut_in_point_r)
    left_middle_angle_1 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_1,
                                                  vertical_middle_cut_in_point_r_1, left_cut_in_point_r, left_cut_out_point_r)
    right_middle_angle_2 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_2,
                                                   vertical_middle_cut_in_point_r_2, right_cut_out_point_r, right_cut_in_point_r)
    left_middle_angle_2 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_2,
                                                  vertical_middle_cut_in_point_r_2, left_cut_in_point_r, left_cut_out_point_r)
    right_middle_angle_3 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_3,
                                                   vertical_middle_cut_in_point_r_3, right_cut_out_point_r, right_cut_in_point_r)
    left_middle_angle_3 = get_two_line_angle_6pin(vertical_middle_cut_out_point_r_3,
                                                  vertical_middle_cut_in_point_r_3, left_cut_in_point_r, left_cut_out_point_r)
    hor_ver_angle = get_two_line_angle_6pin(vertical_middle_cut_in_point_r_1,
                                            vertical_middle_cut_out_point_r_3, horizontal_middle_up_cut_out_point_r,
                                            horizontal_middle_up_cut_in_point_r)
    # 如果是大于0,就证明是小于90度的角,这个时候需要顺时针调,角度值是负的.如果小于0,表示角度大于90度,需要逆时针调整,我们约定需要逆时针调整的时候角度值为正.
    hor_ver_angle = round(90 - abs(hor_ver_angle), 2)

    up_middle_down_midlle_angle = get_two_line_angle_6pin(horizontal_middle_up_cut_out_point_r, horizontal_middle_up_cut_in_point_r,
                                                          horizontal_middle_down_cut_out_point_r,
                                                          horizontal_middle_down_cut_in_point_r)

    cutDisTotal = 0
    cutAreaTotal = 0
    if topRemain != 0:
        cutDis = get_two_point_distance(top_cut_in_point_r, top_cut_out_point_r)
        area = cutDis * (get_two_line_distance([top_cut_out_point_r, top_cut_out_point_r], [boardLeftTopRobot, boardRightTopRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area

    if leftRemain != 0:
        cutDis = get_two_point_distance(left_cut_in_point_r, left_cut_out_point_r)
        area = cutDis * (get_two_line_distance([left_cut_out_point_r, left_cut_in_point_r], [boardLeftTopRobot, boardLeftBottomRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area

    if bottomRemain != 0:
        cutDis = get_two_point_distance(bottom_cut_in_point_r, bottom_cut_out_point_r)
        area = cutDis * (get_two_line_distance([bottom_cut_out_point_r, bottom_cut_in_point_r], [boardLeftBottomRobot, boardRightBottomRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area

    if rightRemain != 0:
        cutDis = get_two_point_distance(right_cut_out_point_r, right_cut_in_point_r)
        area = cutDis * (get_two_line_distance([right_cut_in_point_r, right_cut_out_point_r], [boardRightBottomRobot, boardRightTopRobot]))
        cutDisTotal += cutDis
        cutAreaTotal += area

    length_list = [firstBoardLenBig, secondBoardLenBig, thirdBoardLenBig, firstBoardLenSmall, secondBoardLenSmall, thirdBoardLenSmall,
                   forthBoardLenSmall, fifthBoardLenSmall, sixthBoardLenSmall]
    # 第二刀作为小铡刀第一边的情况
    # angle_list = [top_middle_angle, bottom_middle_angle, left_middle_angle_1, right_middle_angle_1, left_middle_angle_2,
    #               right_middle_angle_2, left_middle_angle_3, right_middle_angle_3, hor_ver_angle,
    #               up_middle_down_midlle_angle,
    #               bottom_downmiddle_angle]
    # 第四刀作为小铡刀第一边的情况
    angle_list = [top_middle_angle, bottom_middle_angle, right_middle_angle_1, left_middle_angle_1, right_middle_angle_2, left_middle_angle_2,
                  right_middle_angle_3, left_middle_angle_3, hor_ver_angle, up_middle_down_midlle_angle, bottom_downmiddle_angle]
    isFirstCut = True if topRemain != 0 else False
    isThirdCut = True if bottomRemain != 0 else False
    cutWidth = round(get_two_point_distance(left_top_cross, right_top_cross) / cp.mm2pix, 2)
    cutLines = [top_cut_in_point_r, top_cut_out_point_r, bottom_cut_in_point_r, bottom_cut_out_point_r, left_cut_in_point_r, left_cut_out_point_r,
                right_cut_in_point_r, right_cut_out_point_r, horizontal_middle_up_cut_in_point_r, horizontal_middle_up_cut_out_point_r,
                horizontal_middle_down_cut_in_point_r, horizontal_middle_down_cut_out_point_r,
                vertical_middle_cut_in_point_r_1, vertical_middle_cut_out_point_r_1,
                vertical_middle_cut_in_point_r_2, vertical_middle_cut_out_point_r_2,
                vertical_middle_cut_in_point_r_3, vertical_middle_cut_out_point_r_3]
    if middleUpIsOk and middleDownIsOk:
        return "ok", cutLines, result_image, cutDisTotal, cutAreaTotal, length_list, angle_list, isFirstCut, isThirdCut, cutWidth
    else:
        return "middleError", cutLines, result_image, cutDisTotal, cutAreaTotal, length_list, angle_list, isFirstCut, isThirdCut, cutWidth


def get_board_length_6(line1, line2, line3, line4, line5, line6, line7, line8, line9, offset1, offset2):
    line_list = [line1, line2, line3, line4, line5, line6, line7, line8, line9]
    line_new = []
    for line in line_list:
        line_tmp = [[line[0][1], line[0][0]], [line[1][1], line[1][0]]]
        line_new.append(line_tmp)
    # 其中line5 line8 line9 是垂直的3条中线,后面把line5分成了3条了,所以为了不改变函数的以前的功能
    line1, line2, line3, line4, line5, line6, line7, line8, line9 = line_new

    # 先求中线中点
    middle_point_hor = get_two_points_middle(line2[0], line2[1])
    hor_left_x = middle_point_hor[0] - offset1 / 2
    hor_right_x = middle_point_hor[0] + offset1 / 2

    hor_k, hor_b = get_line_k_and_b(line2[0], line2[1])
    top_k, top_b = get_line_k_and_b(line1[0], line1[1])

    # 第二条中线的斜率和b值
    hor_k_2, hor_b_2 = get_line_k_and_b(line7[0], line7[1])
    bottom_k, bottom_b = get_line_k_and_b(line3[0], line3[1])

    hor_left_y = hor_left_x * hor_k + hor_b
    hor_right_y = hor_right_x * hor_k + hor_b

    if hor_k == 0:  # 如果中线平行于x轴,则它的垂线的交点可以直接带入x就可以求得结果
        top_left_cross = [hor_left_x, top_k * hor_left_x + top_b]
        top_right_cross = [hor_right_x, top_k * hor_right_x + top_b]
        bottom_left_cross = [hor_left_x, bottom_k * hor_left_x + bottom_b]
        bottom_right_cross = [hor_right_x, bottom_k * hor_right_x + bottom_b]
        middle_left_cross = [hor_left_x, hor_k_2 * hor_left_x + hor_b_2]
        middle_right_cross = [hor_right_x, hor_k_2 * hor_right_x + hor_b_2]
    else:
        # 先求垂线的k和b
        left_k = -1 / hor_k
        left_b = hor_left_y - left_k * hor_left_x
        right_k = -1 / hor_k
        right_b = hor_right_y - right_k * hor_right_x
        top_left_cross = get_two_lines_intersection(left_k, left_b, top_k, top_b)
        top_right_cross = get_two_lines_intersection(right_k, right_b, top_k, top_b)
        bottom_left_cross = get_two_lines_intersection(left_k, left_b, bottom_k, bottom_b)
        bottom_right_cross = get_two_lines_intersection(right_k, right_b, bottom_k, bottom_b)
        middle_left_cross = get_two_lines_intersection(left_k, left_b, hor_k_2, hor_b_2)
        middle_right_cross = get_two_lines_intersection(right_k, right_b, hor_k_2, hor_b_2)
    top_to_middle = round(
        (distance(top_left_cross, (hor_left_x, hor_left_y)) + distance(top_right_cross, (hor_right_x, hor_right_y))) / 2,
        2)  # 第一块板长
    middle_to_middle = round(
        (distance(middle_left_cross, (hor_left_x, hor_left_y)) + distance(middle_right_cross, (hor_right_x, hor_right_y))) / 2,
        2)  # 第二块板长
    top_to_bottom = round((distance(bottom_left_cross, top_left_cross) + distance(bottom_right_cross, top_right_cross)) / 2,
                          2)  # 第三块板长

    # 获取垂直终点的x和y坐标
    # 先获取这个中缝的斜率和b值
    ver_k_1, ver_b_1 = get_line_k_and_b(line5[0], line5[1])
    ver_k_2, ver_b_2 = get_line_k_and_b(line8[0], line8[1])
    ver_k_3, ver_b_3 = get_line_k_and_b(line9[0], line9[1])
    # 获取左边线和右边线的斜率和b值
    left_k, left_b = get_line_k_and_b(line4[0], line4[1])
    right_k, right_b = get_line_k_and_b(line6[0], line6[1])

    # 先找垂直中缝和横着的四条线的交点,第一,三边以及两个水平中缝.
    top_ver_cross = get_two_lines_intersection(ver_k_1, ver_b_1, top_k, top_b)
    up_mid_ver_cross = get_two_lines_intersection(ver_k_1, ver_b_1, hor_k, hor_b)
    down_mid_ver_cross = get_two_lines_intersection(ver_k_2, ver_k_2, hor_k_2, hor_b_2)
    bottom_ver_cross = get_two_lines_intersection(ver_k_3, ver_b_3, bottom_k, bottom_b)

    # 然后求得求得三段板的长度的中点.
    ver_mid_pioint_1 = get_two_points_middle(top_ver_cross, up_mid_ver_cross)
    ver_mid_pioint_2 = get_two_points_middle(up_mid_ver_cross, down_mid_ver_cross)
    ver_mid_pioint_3 = get_two_points_middle(down_mid_ver_cross, bottom_ver_cross)

    ver_1_y = ver_mid_pioint_1[1] - offset2 / 2
    ver_2_y = ver_mid_pioint_1[1] + offset2 / 2

    # 计算第一块板长
    if ver_k_1 is None:  # 如果是垂直于x轴的,点1和点2直接求得即可
        ver_1_x = ver_mid_pioint_1[0]
        ver_2_x = ver_1_x
        # 求它的垂线的k和b
        k1, k2 = 0, 0
        b1, b2 = ver_1_y, ver_2_y
    else:
        # 如果不垂直于x轴,根据斜率和b求的y值
        ver_1_x = (ver_1_y - ver_b_1) / ver_k_1
        ver_2_x = (ver_2_y - ver_b_1) / ver_k_1
        # 求它的垂线的k和b
        k1 = -1 / ver_k_1
        k2 = k1
        b1 = ver_1_y - k1 * ver_1_x
        b2 = ver_2_y - k2 * ver_2_x

    left_cross_1 = get_two_lines_intersection(k1, b1, left_k, left_b)
    left_cross_2 = get_two_lines_intersection(k2, b2, left_k, left_b)
    right_cross_1 = get_two_lines_intersection(k1, b1, right_k, right_b)
    right_cross_2 = get_two_lines_intersection(k2, b2, right_k, right_b)

    right_to_middle_1 = round((distance(right_cross_1, (ver_1_x, ver_1_y)) + distance(right_cross_2, (ver_2_x, ver_2_y))) / 2, 2)
    right_to_left_1 = round((distance(right_cross_1, left_cross_1) + distance(left_cross_2, right_cross_2)) / 2, 2)

    # 算第二块板
    ver_1_y = ver_mid_pioint_2[1] - offset2 / 2
    ver_2_y = ver_mid_pioint_2[1] + offset2 / 2

    if ver_k_2 is None:  # 如果是垂直于x轴的,点1和点2直接求得即可
        ver_1_x = ver_mid_pioint_2[0]
        ver_2_x = ver_1_x
        # 求它的垂线的k和b
        k1, k2 = 0, 0
        b1, b2 = ver_1_y, ver_2_y
    else:
        # 如果不垂直于x轴,根据斜率和b求的y值
        ver_1_x = (ver_1_y - ver_b_2) / ver_k_2
        ver_2_x = (ver_2_y - ver_b_2) / ver_k_2
        # 求它的垂线的k和b
        k1 = -1 / ver_k_2
        k2 = k1
        b1 = ver_1_y - k1 * ver_1_x
        b2 = ver_2_y - k2 * ver_2_x

    left_cross_1 = get_two_lines_intersection(k1, b1, left_k, left_b)
    left_cross_2 = get_two_lines_intersection(k2, b2, left_k, left_b)
    right_cross_1 = get_two_lines_intersection(k1, b1, right_k, right_b)
    right_cross_2 = get_two_lines_intersection(k2, b2, right_k, right_b)

    right_to_middle_2 = round((distance(right_cross_1, (ver_1_x, ver_1_y)) + distance(right_cross_2, (ver_2_x, ver_2_y))) / 2, 2)
    right_to_left_2 = round((distance(right_cross_1, left_cross_1) + distance(left_cross_2, right_cross_2)) / 2, 2)

    ver_1_y = ver_mid_pioint_3[1] - offset2 / 2
    ver_2_y = ver_mid_pioint_3[1] + offset2 / 2

    if ver_k_3 is None:  # 如果是垂直于x轴的,点1和点2直接求得即可
        ver_1_x = ver_mid_pioint_3[0]
        ver_2_x = ver_1_x
        # 求它的垂线的k和b
        k1, k2 = 0, 0
        b1, b2 = ver_1_y, ver_2_y
    else:
        # 如果不垂直于x轴,根据斜率和b求的y值
        ver_1_x = (ver_1_y - ver_b_3) / ver_k_3
        ver_2_x = (ver_2_y - ver_b_3) / ver_k_3
        # 求它的垂线的k和b
        k1 = -1 / ver_k_3
        k2 = k1
        b1 = ver_1_y - k1 * ver_1_x
        b2 = ver_2_y - k2 * ver_2_x

    left_cross_1 = get_two_lines_intersection(k1, b1, left_k, left_b)
    left_cross_2 = get_two_lines_intersection(k2, b2, left_k, left_b)
    right_cross_1 = get_two_lines_intersection(k1, b1, right_k, right_b)
    right_cross_2 = get_two_lines_intersection(k2, b2, right_k, right_b)

    right_to_middle_3 = round((distance(right_cross_1, (ver_1_x, ver_1_y)) + distance(right_cross_2, (ver_2_x, ver_2_y))) / 2, 2)
    right_to_left_3 = round((distance(right_cross_1, left_cross_1) + distance(left_cross_2, right_cross_2)) / 2, 2)
    left_to_middle_1 = right_to_left_1 - right_to_middle_1
    left_to_middle_2 = right_to_left_2 - right_to_middle_2
    left_to_middle_3 = right_to_left_3 - right_to_middle_3
    # 第二刀作为小铡刀第一边的情况:
    # return top_to_middle, middle_to_middle, (top_to_bottom - top_to_middle - middle_to_middle), \
    #        left_to_middle_1, right_to_middle_1, left_to_middle_2, right_to_middle_2, left_to_middle_3, right_to_middle_3
    #
    # 第四刀作为小铡刀第一边的情况:
    return top_to_middle, middle_to_middle, (top_to_bottom - top_to_middle - middle_to_middle), right_to_middle_1, left_to_middle_1, \
        right_to_middle_2, left_to_middle_2, right_to_middle_3, left_to_middle_3


def get_horizontal_middle_line(lineUP, lineDown, middleX):
    upK, upB = lineUP
    downK, downB = lineDown
    upPoint = (middleX, upK * middleX + upB)
    downPoint = (middleX, downK * middleX + downB)
    # 求两个线的角平分线
    middleK = np.tan((np.arctan(upK) + np.arctan(downK)) / 2)
    upB = upPoint[1] - middleK * upPoint[0]
    downB = downPoint[1] - middleK * downPoint[0]

    return (middleK, upB), (middleK, downB)


# 获取垂直角平分线,直接按照4个点的中点连线来求最好,角平分线不好处理. 直接连中点
def get_vertical_middle_cut_line(line1, line2):
    """
    获取垂直方向,也就是竖直方向的中线位置
    :param lin1: 左框的右上角和右下角两个顶点
    :param line2: 右框的左上角和左下角的两个顶点
    :return: 返回中线的斜率和b
    """
    p1, p2 = line1
    p3, p4 = line2
    middleUP = np.add(p1, p3) / 2
    middleDown = np.add(p2, p4) / 2
    verticalMidK, verticalMidB = get_line_k_and_b(middleUP, middleDown)
    return verticalMidK, verticalMidB


# 根据四个点创建向量,然后求得角度.向量的方向是从左到右
def get_two_line_angle_6pin(p1, p2, p3, p4):
    # 注意x和y颠倒. 我们用的右手法则.
    line1 = Line(p1[1], p1[0], p2[1], p2[0])
    line2 = Line(p3[1], p3[0], p4[1], p4[0])
    v1 = line1.vector()
    v2 = line2.vector()
    len1 = line1.length()
    len2 = line2.length()

    # 获去方向
    derection = v1[0] * v2[1] - v1[1] * v2[0]  # 可以判断向量b到向量a的方向,如果是正的,表示向量b在向量a的顺时针方向.由b到a需要逆时针调整.因为我们规定需要逆时针调整的为正值
    # 获取内积
    inner_mul = np.dot(v1, v2)
    # 获取模积
    model_mul = len1 * len2
    # 向量夹角公式
    cosx = inner_mul / model_mul
    if cosx > 1:
        cosx = 1
    top_middle_angle = np.arccos(cosx) * (180 / np.pi)
    top_middle_angle = top_middle_angle if derection > 0 else -top_middle_angle
    return round(top_middle_angle, 2)


def get_line_offset_6p(boxes, totalBoard, totalBoardBox):
    upLeftBox, upRightBox, _, downRightBox, downLeftBox, _ = boxes

    topLinePoints = [upLeftBox[0], upLeftBox[1], upRightBox[0], upRightBox[1]]
    topLinePointsSortedY = sorted(topLinePoints, key=lambda x: x[1])[:2]
    p1, p2 = topLinePointsSortedY

    rightLinePoints = [upRightBox[1], upRightBox[2], downRightBox[1], downRightBox[2]]
    rightLinePointsSortedY = sorted(rightLinePoints, key=lambda x: x[0], reverse=True)[:2]
    p3, p4 = rightLinePointsSortedY

    bottomLinePoints = [downLeftBox[2], downLeftBox[3], downRightBox[2], downRightBox[3]]
    bottomLinePointsSortedY = sorted(bottomLinePoints, key=lambda x: x[1])[:2]
    p5, p6 = bottomLinePointsSortedY

    leftLinePoints = [upLeftBox[0], upLeftBox[3], downLeftBox[0], downLeftBox[3]]
    leftLinePointsSortedY = sorted(leftLinePoints, key=lambda x: x[0])[:2]
    p7, p8 = leftLinePointsSortedY

    w, h = totalBoardBox[1]
    p9, p10, p11, p12 = (0, 0), (w, 0), (w, h), (0, h)
    innerLine1, innerLine2, innerLine3, innerLine4 = [(p1, p2), (p3, p4), (p5, p6), (p7, p8)]
    outterLine1, outterLine2, outterLine3, outterLine4 = [(p9, p10), (p10, p11), (p11, p12), (p12, p9)]

    offsetTop = get_two_line_distance(innerLine1, outterLine1)
    offsetRight = get_two_line_distance(innerLine2, outterLine2)
    offsetBottom = get_two_line_distance(innerLine3, outterLine3)
    offsetLeft = get_two_line_distance(innerLine4, outterLine4)
    return offsetTop, offsetRight, offsetBottom, offsetLeft


if __name__ == '__main__':
    filePath = r"D:\kehui_4p\6pin"
    res, data = db.get_line_cam_check_thres()
    totalHeightMax = data.get("totalHeightMax")
    totalHeightMin = data.get("totalHeightMin")
    boardBreak = False
    calcThresBig = 20
    calcThresSmall = 9
    res1, transMtxData = db.get_trans_mtx_data()
    transMtx = []
    if res1 != "ok":
        errorInfo = "{},标定矩阵获取失败!".format(res1)
        print(errorInfo)
    else:
        mtxLeft = transMtxData.get("mtxLeft")
        mtxRight = transMtxData.get("mtxRight")
        transMtx = [mtxLeft, mtxRight]

    if len(transMtx) == 0:
        mtx = [
            [1, 0, 0],
            [0, 1, 0]
        ]
        transMtx = [mtx, mtx]
    jointNumber = "6"
    remainEdgeMm = [0, 0, 0, 0]
    topRemain, leftRemain, bottomRemain, rightRemain = [int(x * cp.mm2pix) for x in remainEdgeMm]

    keepDir = filePath
    if not os.path.isdir(keepDir):
        keepDir, _ = os.path.split(filePath)

    keepOkPath = os.path.join(keepDir, "ok")
    keepOkResPath = os.path.join(keepDir, "cutlines")
    keepFailPath = os.path.join(keepDir, "fail")
    keepFirstSizeBestRes = os.path.join(keepDir, "first_size_check_best")

    dirList = [keepOkPath, keepOkResPath, keepFailPath, keepFirstSizeBestRes]
    for dirDemo in dirList:
        if not os.path.exists(dirDemo):
            os.mkdir(dirDemo)

    fileNames = []
    if os.path.isfile(filePath):
        filePath, fileName = os.path.split(filePath)
        fileNames.append(fileName)
    else:
        for root, dirs, files in os.walk(filePath):
            if root != filePath:
                continue
            for file in files:
                if file[-4:] != ".bmp":
                    continue
                fileNames.append(file)

    for index, fileName in enumerate(fileNames):
        filePathReal = os.path.join(filePath, fileName)
        box1Offset = box2Offset = box3Offset = box4Offset = [0, 0, 0, 0]
        if jointNumber == "4":
            srcW, srcH, box1Offset, box2Offset, box3Offset, box4Offset = get_width_height_by_image_name_4p(fileName)
            if 0 in box1Offset or 0 in box2Offset or 0 in box3Offset or 0 in box4Offset:
                isFirstBoard = True
            else:
                isFirstBoard = True
        else:
            isFirstBoard = True
            srcW, srcH = get_width_and_height_by_image_name_6p(fileName)

        if srcW is None or srcH is None:
            print("*" * 10 + "第 {} 张图 ({}),图像名称错误,已跳过".format(index + 1, fileName))

        print("*" * 10 + "第 {} 张图 ({})".format(index + 1, fileName) + "*" * 10)
        calcStart = time.time()
        imageSrc = cv.imread(filePathReal, cv.IMREAD_GRAYSCALE)
        totalBoardRes = check_total_board_is_ok(imageSrc, totalHeightMax, totalHeightMin, boardBreak, jointNumber)
        res, hintInfo, totalBoardBox, totalBoardNoAngle, totalBoardOffset, totalBoardThresWithAngle, totalBoardResWithAngle = totalBoardRes
        print("物料检测结果: {}, {}".format(res, hintInfo))
        if isFirstBoard:
            resFirst, boardSizeList, boardResList, upLeftBoard = get_size_check_result_6p(imageSrc, srcW, srcH, calcThresBig, totalBoardBox,
                                                                                          totalBoardNoAngle)
            if resFirst != "error":
                sizeCheckResBest = boardResList[0]
                sizeCheckResBest = get_size_scale_image(sizeCheckResBest, sizeScale=4)
                cv.imwrite(os.path.join(keepFirstSizeBestRes, fileName), sizeCheckResBest)
        boxList6p = None
        if jointNumber == "6":
            res, info, boxList6p = get_boxes_6p(imageSrc, srcW, srcH, calcThresBig, calcThresSmall, totalBoardBox, totalBoardNoAngle)

        topOffset, rightOffset, bottomOffset, leftOffset = get_line_offset_6p(boxList6p, totalBoardNoAngle, totalBoardBox)
        if res:
            lineRes = get_lines_with_boxes_6p(imageSrc, boxList6p, transMtx, topRemain, leftRemain,
                                              bottomRemain, rightRemain, totalBoardBox, totalBoardNoAngle, totalBoardThresWithAngle, totalBoardOffset)
            linesOk, cutLines, imgCut, cutDis, cutAreas, lengthList, angleList, isFirstCut, isThirdCut, cutWidth = lineRes
            print("算法耗时: {}".format(time.time() - calcStart))
            os.remove(filePathReal)
            imageRes = get_size_scale_image(imgCut, sizeScale=4)
            cv.imwrite(os.path.join(keepOkResPath, fileName), imageRes)
            cv.imwrite(os.path.join(keepOkPath, fileName), imageSrc)
            print("识别成功!结果:切割面积:{},切割宽度:{},角度:{},长度:{}".format(cutAreas, cutWidth, angleList, cutLines[-1]))
            continue
        else:
            print("算法耗时: {}".format(time.time() - calcStart))
            cv.imwrite(os.path.join(keepFailPath, fileName), imageSrc)
            os.remove(filePathReal)
            print("识别失败XXXXXXXXXXXXXXXXXXXXXXXXX")
            continue
